/***************************************************************************
 *   Copyright (C) 2008 by Marco Gulino   *
 *   marco.gulino@gmail.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA            *
 ***************************************************************************/
#include "checksummertest.h"
#include "assertionUtils.h"
#include "fileutils.h"
#include "qfileinfointerface.h"
#include "checksummer.h"
#include "qfakefileinfo.h"
#include <QTime>

void CheckSummerTest::init() {
    FileUtils::cleanWorkDir();
}

void CheckSummerTest::shouldCalculateHashForFile()
{
    assertChecksumForAlgoIs("1ecb63094ee3b9b4367fcb3940204fdf", QCryptographicHash::Md5);
    assertChecksumForAlgoIs("fba2f560b468d3d4dd160f3849801b30", QCryptographicHash::Md4);
    assertChecksumForAlgoIs("79a37eeba1ced80254ed61b88dc04ee1fb8766d5", QCryptographicHash::Sha1);
}

void CheckSummerTest::smallFileChecksumTest() {
    QCOMPARE(testFileFor(2 * 1024 * 1024), checksumFromString("b2d1236c286a3c0704224fe4105eca49") );
}

void CheckSummerTest::mediumFileChecksumTest() {
    QCOMPARE(testFileFor(60 * 1024 * 1024), checksumFromString("76c136bc0d680abd978d9934070c01e5") );
}

void CheckSummerTest::hugeFileChecksumTest() {
    QSKIP("too slow, skipping for normal use, but useful for non-regression tests.", SkipAll);

    long oneGB=1024*1024*1024;
    QCOMPARE(testFileFor(5 * oneGB), checksumFromString("ec4bcc8776ea04479b786e063a9ace45") );
}


void CheckSummerTest::shouldReturnChecksummedList() {
    QFileInfoInterface *file1=createTestFile("aaaa", "1", 10 );
    QFileInfoInterface *file2=createTestFile("aaaa", "2", 10 );
    QFileInfoInterface *file3=createTestFile("aaaa", "3", 10 );
    QFileInfoInterface *file4=createTestFile("bbbb", "4", 10 );
    QFileInfoInterface *file5=createTestFile("bbbb", "5", 10 );
    QFileInfoInterface *file6=createTestFile("cccc", "6", 10 );
    QFileInfoInterfaceHash files;
    files.insert(file1->size(), file1);
    files.insert(file2->size(), file2);
    files.insert(file3->size(), file3);
    files.insert(file4->size(), file4);
    files.insert(file5->size(), file5);
    files.insert(file6->size(), file6);
    CheckSummer checkSummer(QCryptographicHash::Md4);
    QFileInfoChecksummedHash checksummed=checkSummer.hashChecksummed(files);
    QCOMPARE2(checksummed.count(), 5);
    QCOMPARE2(checksummed.uniqueKeys().size(), 2);
    QCOMPARE(checksummed.count(file1->checksum()), 3);
    QCOMPARE(checksummed.count(file4->checksum()), 2);
}

void CheckSummerTest::assertChecksumForAlgoIs(const QString &checkSum, QCryptographicHash::Algorithm algo)
{
    QFileInfoInterface *file=createTestFile(500, 1024);
    CheckSummer checkSummer(algo);
    checkSummer.checkSumFile(file);
    QCOMPARE( file->checksum(), checksumFromString(checkSum) );
}



QByteArray CheckSummerTest::testFileFor(qint64 size) {
    QTime timer;
    QFileInfoInterface *file=(new QFakeFileInfo() )->setFilePath("/dev/zero")->setSize(size);
    qint64 sizeInMB=(qint64) (file->size() /1024/1024);
    CheckSummer checkSummer(QCryptographicHash::Md5);
    timer.start();
    checkSummer.checkSumFile(file);
    qDebug() << "Checksumming (" << sizeInMB << " MB) " << "took " << timer.restart() << " ms" << endl;
    return file->checksum();
}


QByteArray CheckSummerTest::checksumFromString(const QString &data)
{
    QByteArray hash;
    for(int pos=0; pos<data.size(); pos+=2) {
        QChar current(data.mid(pos, 2).toInt(0, 16));
        hash+=current;
    }
    return hash;
}

QFileInfoInterface* CheckSummerTest::createTestFile(int size, int multiplier) {
    QString filePath=WORKDIR + "/testFile";
    FileUtils::fileOf(size, multiplier, filePath, 'A');
    return new QFileInfoInterface(QFileInfo( filePath ));
}

QFileInfoInterface* CheckSummerTest::createTestFile(const QString pattern, int multiplier) {
    return createTestFile(pattern, "", multiplier);
}

QFileInfoInterface* CheckSummerTest::createTestFile(const QString pattern, const QString &suffix, int multiplier) {
    QString filePath=WORKDIR + "/testFile" + suffix;
    FileUtils::fileWith(pattern, multiplier, filePath);
    return new QFileInfoInterface(QFileInfo( filePath ));
}

